package com.example.jimmerfast.util;


import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.SneakyThrows;
import org.babyfish.jimmer.sql.JSqlClient;
import org.babyfish.jimmer.sql.ast.Selection;
import org.babyfish.jimmer.sql.ast.mutation.*;
import org.babyfish.jimmer.sql.ast.query.ConfigurableRootQuery;
import org.babyfish.jimmer.sql.ast.query.Example;
import org.babyfish.jimmer.sql.ast.query.MutableRootQuery;
import org.babyfish.jimmer.sql.ast.table.Table;
import org.babyfish.jimmer.sql.ast.table.spi.TableProxy;
import org.babyfish.jimmer.sql.fetcher.Fetcher;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.GenericTypeResolver;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

public class JimmerCrudServiceImpl<E, ID> implements JimmerCrudService<E,ID> {

    protected JSqlClient sqlClient;
    protected final Class<E> entityType;

    private final TableProxy<E> table;


    @SneakyThrows
    public JimmerCrudServiceImpl() {
        sqlClient = SpringUtil.getBean(JSqlClient.class);
        Class<?>[] typeArguments = GenericTypeResolver
                .resolveTypeArguments(this.getClass(), JimmerCrudService.class);
        entityType = (Class<E>) typeArguments[0];


        Class<?> tableClass = Class.forName(entityType.getName() + "Table");
        Field field = ReflectUtil.getField(tableClass, "$");
        table = (TableProxy<E>) ReflectUtil.getStaticFieldValue(field);
    }

    @Override
    @Deprecated
    public SimpleSaveResult<E> insert(E entity) {
        return sqlClient.getEntities().saveCommand(entity).setMode(SaveMode.INSERT_ONLY).execute();
    }

    @Override
    public SimpleSaveResult<E> update(E entity) {
        return sqlClient.getEntities().saveCommand(entity).setMode(SaveMode.UPDATE_ONLY).execute();
    }

    @Override
    public SimpleSaveResult<E> save(E entity) {
        return sqlClient.getEntities().save(entity);
    }

    @Override
    public SimpleEntitySaveCommand<E> saveCommand(E entity) {
        return sqlClient.getEntities().saveCommand(entity);
    }

    @Override
    public DeleteResult deleteById(ID id) {
        return sqlClient.getEntities().delete(entityType, id);
    }

    @Override
    public DeleteResult deleteByIds(Collection<ID> list) {
        return sqlClient.getEntities().deleteAll(entityType, list);
    }

    @Override
    public E findById(ID id) {
        return findById(id, null);
    }


    @Override
    public E findById(ID id, Fetcher<E> fetcher) {
        if(fetcher != null) {
            return sqlClient.getEntities().findById(fetcher, id);

        }
        return sqlClient.getEntities().findById(entityType, id);
    }

    @Override
    public List<E> findByIds(Collection<ID> idList) {
        return findByIds(idList, null);
    }

    @Override
    public List<E> findAll() {
        return findAll(null);
    }

    @Override
    public List<E> findByIds(Collection<ID> idList, Fetcher<E> fetcher) {
        if(fetcher != null) {
            return sqlClient.getEntities().findByIds(fetcher, idList);
        }else {
            return sqlClient.getEntities().findByIds(entityType,idList);
        }
    }

    @Override
    public List<E> findAll(Fetcher<E> fetcher) {
        if(fetcher != null){
            return sqlClient.getEntities().findAll(fetcher);
        }
        return sqlClient.getEntities().findAll(entityType);
    }

    @Override
    public PageResult<E> page(PageParam pageParam, ConfigurableRootQuery<? extends Table<E>, E> condition) {
        return JimmerUtil.page(pageParam, condition);
    }

    @Override
    public PageResult<E> page(PageParam pageParam) {
        ConfigurableRootQuery<TableProxy<E>, E> select = sqlClient.createQuery(table).select(table);
        return page(pageParam, select);
    }

    @NotNull
    @Override
    public MutableRootQuery<? extends TableProxy<E>> query() {
        return sqlClient.createQuery(table);
    }

    @Override
    public PageResult<E> page(PageParam page, Fetcher<E> fetcher) {
        Selection<E> selection = table;
        if(fetcher != null){
            selection = table.fetch(fetcher);
        }
        ConfigurableRootQuery<TableProxy<E>, E> select = sqlClient.createQuery(table).select(selection);
        return page(page, select);
    }

    @Override
    public PageResult<E> pageByExample(PageParam pageParam, Example<E> example) {
        return pageByExample(pageParam, example, null);
    }

    @Override
    public PageResult<E> pageByExample(PageParam pageParam, Example<E> example, Fetcher<E> fetcher) {
        Selection<E> selection = table;
        if(fetcher != null){
            selection = table.fetch(fetcher);
        }
        ConfigurableRootQuery<TableProxy<E>, E> select = sqlClient.createQuery(table).where(table.eq(example)).select(selection);
        return JimmerUtil.page(pageParam, select);
    }

    @Override
    public List<E> findByExample(Example<E> example) {
        return findByExample(example,null);
    }


    @Override
    public List<E> findByExample(Example<E> example, Fetcher<E> fetcher) {
        if(fetcher != null){
            return sqlClient.getEntities().findByExample(example, fetcher);
        }
        return sqlClient.getEntities().findByExample(example);
    }

    @Override
    public MutableUpdate createUpdate(){
        return sqlClient.createUpdate(table);
    }
}
